package com.jeremyfeinstein.conference;

import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.alibaba.fastjson.JSON;
import com.intel.webrtc.base.ActionCallback;
import com.intel.webrtc.base.ClientContext;
import com.intel.webrtc.base.LocalCameraStream;
import com.intel.webrtc.base.LocalStream;
import com.intel.webrtc.base.RemoteScreenStream;
import com.intel.webrtc.base.RemoteStream;
import com.intel.webrtc.base.WoogeenException;
import com.intel.webrtc.conference.ConferenceClient;
import com.intel.webrtc.conference.ConferenceClient.ConferenceClientObserver;
import com.intel.webrtc.conference.ConferenceClientConfiguration;
import com.intel.webrtc.conference.PublishOptions;
import com.intel.webrtc.conference.RecordAck;
import com.intel.webrtc.conference.RecordOptions;
import com.intel.webrtc.conference.RemoteMixedStream;
import com.intel.webrtc.conference.User;
import com.jeremyfeinstein.event.ExitConferenceEvent;
import com.jeremyfeinstein.event.OnStreamRemoveEvent;
import com.jeremyfeinstein.event.ShareDeskTopEvent;
import com.jeremyfeinstein.gson.ChatMessage;
import com.jeremyfeinstein.gson.CreateTokenResponse;
import com.jeremyfeinstein.gson.JoinResponse;
import com.jeremyfeinstein.gson.MeetingUser;
import com.jeremyfeinstein.okhttputil.callback.StringCallback;
import com.jeremyfeinstein.utils.AppConstants;
import com.jeremyfeinstein.utils.ConferenceApp;
import com.jeremyfeinstein.utils.ConfigUtil;
import com.jeremyfeinstein.utils.SPUtil;
import com.jeremyfeinstein.utils.ToastUtil;
import com.jeremyfeinstein.utils.YCHSInstance;
import com.jeremyfeinstein.utils.YCHSWebSocketAPI;
import com.jeremyfeinstein.utils.YCHShttpAPI;
import com.orhanobut.logger.Logger;

import org.webrtc.EglBase;
import org.webrtc.PeerConnection.IceServer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;

import de.greenrobot.event.EventBus;
import okhttp3.Call;

public class YCHSConferenceClient implements ConferenceClientObserver {
	protected static final String TAG = YCHSConferenceClient.class.getSimpleName();

	// 角色编码，1=主持人，2=助理，3=参会人员，4=听众
	public static final String ROLE_PRESENTER = "1";
	public static final String ROLE_ASSISTANT = "2";
	public static final String ROLE_PARTICIPANTS = "3";
	public static final String ROLE_LISTENER = "4";
	// 互动讨论发送对象,1=全员，2=私聊
	public static final String SEND_ALL = "1";
	public static final String SEND_SINGLE = "2";

	private static YCHSConferenceClient instance;
	private ConferenceClient mConferenceClient;
	private String meetingId;
	private String mcu_role;
	private String mcu_roomid;
	private String meeting_type;
	private List<MeetingUser> userList;
	private List<ChatMessage> chatMessages;
	private HashMap<String,ChatMessage> msgMap = new HashMap<>();
	private JoinResponse mJoinResponse;
	private MeetingUser mUser;

	private YCHSConferenceClient() {
		EglBase rootEglBase = new EglBase();
		ClientContext.setApplicationContext(ConferenceApp.getApp(), rootEglBase.getContext());
		ConferenceClientConfiguration config = new ConferenceClientConfiguration();
		List<IceServer> iceServers = new ArrayList<IceServer>();
		// iceServers.add(new IceServer(stunAddr));
		String turnUrl = "";
//		if (AppConstants.isLocalMeeting){
//		turnUrl = "turn:"+AppConstants.turnAddrLocal+":" + ConfigUtil.getInstance().getLocalPort3() +"?transport=tcp";
		turnUrl = "turn:"+ConfigUtil.getInstance().getMcuServerIP()+":" + ConfigUtil.getInstance().getLocalPort3() +"?transport=tcp";
//		}else {
//			turnUrl = "turn:"+AppConstants.turnAddrRemote+":" + ConfigUtil.getApp().getLocalPort3() +"?transport=tcp";
//		}
		Log.e(TAG, "turnAddrTCP:" + turnUrl);
		iceServers.add(new IceServer(turnUrl, "ebtadmin", "ebt123"));
//		if(null != ConfigUtil.getApp().getLocalPort5()){
//			iceServers.add(new IceServer(AppConstants.turnAddrTCP2, "ebtadmin",
//					"ebt123"));
//		}

		// iceServers.add(new IceServer(turnAddrUDP, "woogeen", "master"));
		try {
			config.setIceServers(iceServers);
		} catch (WoogeenException e1) {
			e1.printStackTrace();
		}
		mConferenceClient = new ConferenceClient(config);
		mConferenceClient.addObserver(this);
		userList = new ArrayList<>();
		chatMessages = new ArrayList<>();
		mJoinResponse = new JoinResponse();
	}

	public static YCHSConferenceClient getInstance() {
		//if (instance == null) {
		//	synchronized (YCHSConferenceClient.class){
		if (instance == null){
			instance = new YCHSConferenceClient();
		}
		//}
		//}
		return instance;
	}

	public void clear() {
		meetingId = "";
		mcu_role = "";
		mcu_roomid = "";
	}

	public void setMeetingId(String meetingId) {
		this.meetingId = meetingId;
	}

	public String getMeetingId() {
		return meetingId;
	}

	public void setMCURoomId(String mcu_roomid) {
		this.mcu_roomid = mcu_roomid;
	}

	public String getMCURoomId() {
		return mcu_roomid;
	}

	public void setMCURole(String mcu_role) {
		this.mcu_role = mcu_role;
	}

	public String getMCURole() {
		return mcu_role;
	}

	public boolean hasSwitchCameraPermission() {
		return !ROLE_LISTENER.equals(mcu_role);
	}

	public boolean hasVideoPermission() {
		return !ROLE_LISTENER.equals(mcu_role);
	}

	public boolean hasAudioPermission() {
		return !ROLE_LISTENER.equals(mcu_role);
	}

	public boolean hasSharePermission() {
		return ROLE_PRESENTER.equals(mcu_role);
	}

	public boolean hasConferenceControlPermission() {
		return ROLE_PRESENTER.equals(mcu_role)
				|| ROLE_ASSISTANT.equals(mcu_role);
	}

	public void addChatMessage(ChatMessage chatMessage) {
		chatMessages.add(chatMessage);
	}

	public List<ChatMessage> getChatMessages() {
		return chatMessages;
	}




	public static Hashtable<String, Integer> getMinResolution(
			RemoteMixedStream mixedStream) {
		List<Hashtable<String, Integer>> lists = mixedStream
				.getSupportedResolutions();
		int minR = Integer.MAX_VALUE;
		Hashtable<String, Integer> minResolution = null;
		for (Hashtable<String, Integer> resolution : lists) {
			if (minR > resolution.get("width") * resolution.get("height")) {
				minResolution = resolution;
				minR = resolution.get("width") * resolution.get("height");
			}
		}
		return minResolution;
	}


	public void chatMessage(String message, String sendObject, String toUserCode) {
		ChatMessage chatMessage = new ChatMessage();
		chatMessage.setMeetingId(meetingId);
		chatMessage.setMessage(message);
		chatMessage.setSendObject(sendObject);
		chatMessage.setToUserCode(toUserCode);
		chatMessage.setUserCode(YCHSInstance.getInstance().getLoginUser()
				.getUSER_CODE());
		chatMessage.setUserName(YCHSInstance.getInstance().getLoginUser()
				.getUSER_NAME());
		YCHSWebSocketAPI.getInstance().chatMessage(chatMessage);
		chatMessages.add(chatMessage);
	}



	public MeetingUser getUserByUserCode(String userCode) {
		for (MeetingUser muser : userList) {
			if (userCode.equals(muser.getUserSN())) {
				return muser;
			}
		}
		return null;
	}

	public void joinRoom(final Context context, String username,
						 final String flag, final ActionCallback<User> actionCallback) {
		Log.d(TAG, "joinRoom......");
		String url = (String) SPUtil.get(AppConstants.MCU_ADDRESS, "");
//		if (AppConstants.isLocalMeeting){
//			url = ConfigUtil.getApp().getLocalSocketUrl();
//		}else {
//			url = ConfigUtil.getApp().getRemoteSocketUrl();
//		}
		YCHShttpAPI.createToken(context,url, username,getMeetingId(), mcu_roomid,
				new StringCallback() {
					@Override
					public void onResponse(String response) {
						Log.d(TAG, "createToken: "+response);
						String TokenString;
						CreateTokenResponse createTokenResponse = JSON.parseObject(response,
								CreateTokenResponse.class);
						if ("0".equals(createTokenResponse.getResultCode())) {
							if (AppConstants.isLocalMeeting) {
								//response = ConfigUtil.setMCUIP(response, ConfigUtil.getApp().getRemoteUrl(), ConfigUtil.getApp().getLocalPort4());
								Logger.e("createToken :" + "response :" + createTokenResponse.getTokenStr() + " mcuServerIp = " + ConfigUtil.getInstance().getMcuServerIP()
										+ "localPort4= " + ConfigUtil.getInstance().getLocalPort4());
								if (TextUtils.isEmpty(createTokenResponse.getTokenStr())) {
									ToastUtil.showToast("token为空");
									return;
								}
								TokenString = ConfigUtil.setMCUIP(createTokenResponse.getTokenStr(), ConfigUtil.getInstance().getMcuServerIP(), ConfigUtil.getInstance().getLocalPort4()); //集群
								Log.e("createtoken true:", ConfigUtil.getInstance().getRemoteUrl() + "," + ConfigUtil.getInstance().getLocalPort4());
							} else {
								TokenString = ConfigUtil.setMCUIP(createTokenResponse.getTokenStr(), ConfigUtil.getInstance().getAgentServer(), ConfigUtil.getInstance().getLocalPort4());
								Log.e("createtoken flase:", ConfigUtil.getInstance().getAgentServer() + ":" + ConfigUtil.getInstance().getLocalPort4());
							}
							join(TokenString, flag, actionCallback);
						}else {
							ToastUtil.showToast(createTokenResponse.getErrorMessage());
						}
					}

					@Override
					public void onError(Call call, int statusCode, Exception e) {
						actionCallback.onFailure(new WoogeenException("加入互动失败，网络连接不稳定！"));
					}
				});
	}

	public void join(String token, final String flag, final ActionCallback<User> actionCallback) {
		Log.d(TAG, "join......");
		try {
			mConferenceClient.join(token, new ActionCallback<User>() {
				@Override
				public void onSuccess(User myself) {
					Log.d(TAG, "My client Id: " + myself.getId());
					YCHSWebSocketAPI.getInstance().join(meetingId, myself.getId(), mcu_role, flag);
					actionCallback.onSuccess(myself);
				}

				@Override
				public void onFailure(final WoogeenException e) {
					actionCallback.onFailure(e);
				}
			});
		} catch (Exception e) {
			Toast.makeText(ConferenceApp.getApp().getApplicationContext(),
					"link mcu socket error", Toast.LENGTH_LONG).show();
		}

	}

	public void shareVideo(String streamId) {
		MeetingUser mUser = getMeetringUserByStreamId(streamId);
		String beShareUserCode = "";
		if(mUser != null){
			beShareUserCode = mUser.getUserSN();
		}
		YCHSWebSocketAPI.getInstance().shareVideo(streamId, mcu_roomid, beShareUserCode);
	}


	public MeetingUser getMeetringUserByStreamId(String streamId) {
		if (TextUtils.isEmpty(streamId)) {
			return null;
		}
		List<MeetingUser> meetingUsers = YCHSConferenceClient.getInstance()
				.getUserList();
		Log.e("GetTime",meetingUsers.toString());
		for (MeetingUser meetingUser : meetingUsers) {
			/*if(meetingUser.getStreamId().equals(streamId)){
				return meetingUser;
			}*/

			if(streamId.equals(meetingUser.getStreamId())){
				return meetingUser;
			}
		}
		return null;
	}
	public void stopShare() {
		YCHSWebSocketAPI.getInstance().stopShare();
	}

	public void getMeetingUserListAlone() {
		YCHSWebSocketAPI.getInstance().getMeetingUserListAlone(meetingId);
	}
	public void setContrlDevice(String status, String action, String userCode) {
		YCHSWebSocketAPI.getInstance().controlDevice(status, action, userCode);
	}


	public ConferenceClient getConferenceClient() {
		return mConferenceClient;
	}

	public List<RemoteStream> getRemoteStreams() {
		return mConferenceClient.getRemoteStreams();
	}

	public RemoteStream getRemoteStreamsById(String streamId) {
		if (TextUtils.isEmpty(streamId)) {
			return null;
		}
		List<RemoteStream> rss = mConferenceClient.getRemoteStreams();
		for (RemoteStream rs : rss) {
			if (streamId.equals(rs.getId())) {
				return rs;
			}
		}
		return null;
	}

	public void getRegion(RemoteStream stream,
						  ActionCallback<String> actionCallback) {
		mConferenceClient.getRegion(stream, actionCallback);
	}

	public void setRegion(RemoteStream stream, String replaceRegion,
						  ActionCallback<Void> actionCallback) {
		mConferenceClient.setRegion(stream, replaceRegion, actionCallback);
	}

	public void publish(LocalCameraStream localStream, PublishOptions option,
						ActionCallback<Void> actionCallback) {
		// PublishOptions option = new PublishOptions();
		// option.setMaximumVideoBandwidth(150);
		// option.setMaximumAudioBandwidth(20);
		// option.setVideoCodec(VideoCodec.VP8);
		mConferenceClient.publish(localStream, option, actionCallback);
	}

	public void startRecorder(final RecordOptions opt, final ActionCallback< RecordAck > callback) {
		mConferenceClient.startRecorder(opt, callback);
	}

	public void unpublish(LocalStream localStream,
						  ActionCallback<Void> actionCallback) {
		mConferenceClient.unpublish(localStream, actionCallback);
	}

	public void leave(ActionCallback<Void> actionCallback) {
		mConferenceClient.leave(actionCallback);
		clear();
	}

	@Override
	public void onMessageReceived(String arg0, String arg1, boolean arg2) {
		//YCHSWebSocketAPI.getApp().getMeetingUserListAlone(meetingId);
	}

	@Override
	public void onRecorderAdded(String arg0) {

	}

	@Override
	public void onRecorderContinued(String arg0) {

	}

	@Override
	public void onRecorderRemoved(String arg0) {

	}

	@Override
	public void onServerDisconnected() {
		Log.d(TAG, "onServerDisconnected.....");
		ExitConferenceEvent event = new ExitConferenceEvent();
		EventBus.getDefault().post(event);
	}

	@Override
	public void onStreamAdded(RemoteStream arg0) {
		Log.d(TAG, "onStreamAdded.....");
		Log.d(TAG, "onStreamAdded....." + YCHSInstance.getInstance().getLoginUser().getUSER_NAME());
		MeetingUser meetingUser2 = null;
		if (arg0 instanceof RemoteScreenStream) {
			ShareDeskTopEvent event = new ShareDeskTopEvent(arg0, 1);
			EventBus.getDefault().post(event);
		}
		YCHSWebSocketAPI.getInstance().getMeetingUserListAlone(meetingId);
		List<MeetingUser> userList = YCHSConferenceClient.getInstance()
				.getUserList();
		for (MeetingUser meetingUser : userList) {
			if (arg0 != null && arg0.getId().equals(meetingUser.getStreamId())) {
				meetingUser2 = meetingUser;
				break;
			}
		}
		//Log.d("fail", "muser....." + mUser.getName());
		if (meetingUser2 != null) {
			if (YCHSInstance.getInstance().getLoginUser().getUSER_CODE()
					.equals(meetingUser2.getUserSN())) {
				if (YCHSConferenceClient.getInstance().ROLE_PRESENTER
						.equals(meetingUser2.getRole())) {

					if (arg0 != null) {
						YCHSConferenceClient.getInstance().setRegion(arg0, "1",
								new ActionCallback<Void>() {

									@Override
									public void onSuccess(Void arg0) {
										// TODO Auto-generated method stub
										Log.d("fail", "setRegion success onStreamAdded 1 user: " );

									}

									@Override
									public void onFailure(WoogeenException arg0) {
										// TODO Auto-generated method stub
										Log.d("fail", "setRegion onFailure onStreamAdded 1 user: "
												+ arg0.getMessage());
									}
								});
					}
				} else if (YCHSConferenceClient.getInstance().ROLE_ASSISTANT
						.equals(meetingUser2.getRole())) {

					if (arg0 != null) {
						YCHSConferenceClient.getInstance().setRegion(arg0, "2",
								new ActionCallback<Void>() {

									@Override
									public void onSuccess(Void arg0) {
										// TODO Auto-generated method stub
										Log.d("fail", "setRegion success onStreamAdded 2");

									}

									@Override
									public void onFailure(WoogeenException arg0) {
										// TODO Auto-generated method stub
										Log.d("fail", "setRegion onFailure onStreamAdded 2"
												+ arg0.getMessage());
									}
								});
					}
				}
			}
		}

	}

	@Override
	public void onStreamRemoved(RemoteStream arg0) {
		//当视频流离开的时候发出
		Log.d(TAG, "onStreamRemoved.....");
		OnStreamRemoveEvent event0 = new OnStreamRemoveEvent();
		event0.setStreamId(arg0.getId());
		EventBus.getDefault().post(event0);
		if (arg0 instanceof RemoteScreenStream) {
			ShareDeskTopEvent event = new ShareDeskTopEvent(arg0, 0);
			EventBus.getDefault().post(event);
			YCHSWebSocketAPI.getInstance().getMeetingUserListAlone(meetingId);
		} else {
			YCHSWebSocketAPI.getInstance().getMeetingUserListAlone(meetingId);
		}
	}

	@Override
	public void onUserJoined(User arg0) {
		Log.d(TAG, "onUserJoined.....");
		YCHSWebSocketAPI.getInstance().getMeetingUserListAlone(meetingId);
	}

	@Override
	public void onUserLeft(User arg0) {
		YCHSWebSocketAPI.getInstance().getMeetingUserListAlone(meetingId);
	}

	public List<MeetingUser> getUserList() {
		return userList;
	}

	public void setUserList(List<MeetingUser> userList) {
		this.userList = userList;
	}

	public JoinResponse getJoinResponse() {
		return mJoinResponse;
	}

	public void setJoinResponse(JoinResponse joinResponse) {
		this.mJoinResponse = joinResponse;
	}

	public List<MeetingUser> getUserListWithoutLoginUser() {
		if (null != userList) {
			Iterator<MeetingUser> iterator = userList.iterator();
			while (iterator.hasNext()) {
				if (iterator
						.next()
						.getUserSN()
						.equals(ConfigUtil.getInstance().getLoginUser().getUSER_CODE())) {
					iterator.remove();
				}
			}
		}
		return userList;
	}

	public String getMeeting_type() {
		return meeting_type;
	}

	public void setMeeting_type(String meeting_type) {
		this.meeting_type = meeting_type;
	}

}
